package model;

import java.util.ArrayList;
import java.util.List;

public class Problem {
	List<Resource> resources;
	List<Machine> machines;
	List<Process> processes;
	List<Service> services;
	List<BalanceObjective> balanceObjectives;
	int weightProcessMoveCost;
	int weightServiceMoveCost;
	int weightMachineMoveCost;

	public int getWeightProcessMoveCost() {
		return weightProcessMoveCost;
	}

	public void setWeightProcessMoveCost(int weightProcessMoveCost) {
		this.weightProcessMoveCost = weightProcessMoveCost;
	}

	public int getWeightServiceMoveCost() {
		return weightServiceMoveCost;
	}

	public void setWeightServiceMoveCost(int weightServiceMoveCost) {
		this.weightServiceMoveCost = weightServiceMoveCost;
	}

	public int getWeightMachineMoveCost() {
		return weightMachineMoveCost;
	}

	public void setWeightMachineMoveCost(int weightMachineMoveCost) {
		this.weightMachineMoveCost = weightMachineMoveCost;
	}

	public Problem() {
		resources = new ArrayList<Resource>();
		machines = new ArrayList<Machine>();
		processes = new ArrayList<Process>();
		services = new ArrayList<Service>();
		balanceObjectives = new ArrayList<BalanceObjective>();
	}

	public void addResource(Resource resource) {
		resource.setId("r" + resources.size());
		resources.add(resource);
	}

	public List<Resource> getResources() {
		return resources;
	}

	public void addMachine(Machine machine) {
		machine.setId("m" + machines.size());
		machines.add(machine);
	}

	public List<Machine> getMachines() {
		return machines;
	}

	public void addService(Service service) {
		service.setId(services.size());
		services.add(service);
	}

	public Resource getResourceByIndex(int index) {
		return resources.get(index);
	}

	public List<Service> getServices() {
		return services;
	}

	public void addProcess(Process process) {
		process.setId("p" + processes.size());
		processes.add(process);
	}

	public List<Process> getProcesses() {
		return processes;
	}

	public List<BalanceObjective> getBalanceObjectives() {
		return balanceObjectives;
	}

	public void addBalanceObjective(BalanceObjective bo) {
		balanceObjectives.add(bo);
	}

	public void printDetails() {
		StringBuilder sb = new StringBuilder();
		sb.append("Resources =" + resources.size());
		sb.append("\n");
		for (Resource resource : resources) {
			sb.append(resource.toString());
			sb.append("\n");
		}
		sb.append("Machines  =" + machines.size());
		sb.append("\n");
		for (Machine machine : machines) {
			sb.append(machine.toString());
			sb.append("\n");
		}

		sb.append("Services  =" + services.size());
		sb.append("\n");
		for (Service service : services) {
			sb.append(service.toString());
			sb.append("\n");
		}

		sb.append("Processes  =" + processes.size());
		sb.append("\n");
		for (Process process : processes) {
			sb.append(process.toString());
			sb.append("\n");
		}

		sb.append("Balance Objectives =" + balanceObjectives.size());
		sb.append("\n");
		for (BalanceObjective bo : balanceObjectives) {
			sb.append(bo);
			sb.append("\n");
		}

		sb.append("\n");
		sb.append(String.format("weight process move cost=%d\n",
				weightProcessMoveCost));
		sb.append(String.format("weight service move cost=%d\n",
				weightServiceMoveCost));
		sb.append(String.format("weight machine move cost=%d\n",
				weightMachineMoveCost));
		System.out.println(sb.toString());
	}

	// ################################################

	// M x R
	public int[][] machinesByResourcesCapacity;
	// P x R
	public int[][] processesByResourcesRequirement;
	// P
	public int[] servicesOfProcesses;
	// M
	public int[] machines_locations;
	// M
	public int[] machines_neighborhoods;
	// S
	public List<Integer>[] service_dependencies;

	public void generateDataStructures() {
		machinesByResourcesCapacity = new int[machines.size()][resources.size()];
		for (Machine machine : machines) {
			int m_i = machines.indexOf(machine);
			for (Resource resource : resources) {
				int r_i = resources.indexOf(resource);
				machinesByResourcesCapacity[m_i][r_i] = machine
						.getCapacityFor(resource.getId());
			}
		}

		processesByResourcesRequirement = new int[processes.size()][resources
				.size()];
		for (Process process : processes) {
			int p_i = processes.indexOf(process);
			for (Resource resource : resources) {
				int r_i = resources.indexOf(resource);
				processesByResourcesRequirement[p_i][r_i] = process
						.getRequirementFor(resource.getId());
			}
		}

		servicesOfProcesses = new int[processes.size()];
		for (Process process : processes) {
			int p_i = processes.indexOf(process);
			servicesOfProcesses[p_i] = process.service;
		}

		machines_locations = new int[machines.size()];
		for (Machine machine : machines) {
			int m_i = machines.indexOf(machine);
			machines_locations[m_i] = machine.location;
		}

		machines_neighborhoods = new int[machines.size()];
		for (Machine machine : machines) {
			int m_i = machines.indexOf(machine);
			machines_neighborhoods[m_i] = machine.neighborhood;
		}

		service_dependencies = new List[services.size()];
		for (Service aService : services) {
			int s_i = services.indexOf(aService);
			service_dependencies[s_i] = new ArrayList<Integer>();
			for (Integer b_service_id : aService.dependsOn) {
				service_dependencies[s_i].add(b_service_id);
			}
		}
	}

}
